import { html, NE, reactive, renderMaps } from 'nvagir'
import './DatePicker'
import './PlanModal.less'

/**
 * Plan modal props for different types of modals
 */
type PlanModalProps = {
  header: string
  onClose: VoidFunction
  onConfirm: (formData: Plan) => void
  plan?: Plan
}

const waysMap: Record<string, string[]> = {
  无: [],
  前端: ['JS', 'CSS', 'HTML', 'TS', 'React', 'Vue', 'Angular'],
  后端: ['Node.js', 'Go', 'Rust', 'Java', 'PHP', 'Python'],
}

/**
 * Plan way component
 * @param way Plan way
 * @param changeWay
 * @returns An object contains the outermost element,
 *   i.e. <li> in the current component
 */
const Way = (way: string, changeWay: (way: string) => void) => {
  const { el } = html`<li
    n@name="li"
    n@click=${() => changeWay(way)}
    class="plan-way-item"
  >
    ${way}
  </li>`

  const result: NE<'way'> = {
    name: 'way',
    el,
  }
  return result
}

/**
 * Tag component of a plan way
 * @param tag
 * @param toggleActive Toggle the selected and unselected tags
 * @param isActive The tag is not selected default
 * @returns An object contains the outermost element,
 *   i.e. <span> in the current component
 */
const WayTag = (tag: string, toggleActive: () => void, isActive = false) => {
  /**
   * When the tag is selected, add the active class for style
   */
  const handlerClick = () => {
    doms.tag.classList.toggle('active')
    toggleActive()
  }

  /**
   * el - An object that contains the outermost element(container).
   * doms - An object that contains some captured elements for control.
   */
  const { el, doms } = html<{
    tag: HTMLSpanElement
  }>`<span
    n@name="tag"
    n@click=${handlerClick}
    class="plan-tag ${isActive ? 'active' : ''}"
    >${tag}</span
  >`

  const component: NE<'wayTag'> = {
    name: 'wayTag',
    el,
  }
  return component
}

/**
 * Make different modals based on different props.
 * @param PlanModalProps An object for plan modal props
 * @returns el - An object that contains the outermost element(container).
 */
export const PlanModal = ({
  header,
  onClose,
  onConfirm,
  plan = {
    title: '',
    comment: '',
    dueDate: '',
    details: [],
    way: '无',
    tags: [],
  },
}: PlanModalProps) => {
  const handlePropTags = (way: string, tags: string[]) => {
    const currHas = new Set(tags)
    return waysMap[way].map(tag => (currHas.has(tag) ? tag : ''))
  }

  const data = {
    way: plan.way,
    tags: handlePropTags(plan.way, plan.tags),
  }

  /**
   * When click the cancel or close button, close the modal
   */
  const handleClose = () => {
    el.dom.remove()
    onClose()
  }

  /**
   * When click the confirm button, get the form data and pass to onConfirm
   */
  const handleConfirm = () => {
    el.dom.remove()
    const formData = new FormData(doms.form)
    // @ts-ignore
    const dueDate = doms.datePicker.datePickerInput.value
    const result = {
      title: formData.get('plan-title') as string,
      comment: formData.get('plan-description') as string,
      dueDate: dueDate as string,
      details: [],
      way: formData.get('plan-way') as string,
      tags: data.tags.filter(Boolean),
    }
    console.log(result)
    onConfirm(result)
  }

  /**
   * If the input box of plan way is clicked, show the plan way menu
   */
  const showPlanWayMenu = () => {
    doms.planWayMenu.classList.toggle('hidden')
  }

  /**
   * If the input box of plan way is not clicked, hide the plan way menu
   */
  const handlePlanWayMenuClickOut = (evt: MouseEvent) => {
    const target = evt.target as HTMLElement
    if (target !== doms.planWayInput) {
      doms.planWayMenu.classList.add('hidden')
    }
  }

  /**
   * Toggle the selected and unselected tags
   * @param tag
   * @param i The index of selected tag in data
   */
  const toggleActive = (tag: string, i: number) => {
    if (data.tags[i]) data.tags[i] = ''
    else data.tags[i] = tag
  }

  /**
   * el - An object that contains the outermost element(container).
   * doms - An object that contains some captured elements for control.
   */
  const { el, doms, components } = html<
    {
      form: HTMLFormElement
      datePicker: HTMLElement
      planWayMenu: HTMLUListElement
      planWayInput: HTMLInputElement
      planTagsWrap: HTMLElement
      tagsContainer: HTMLUListElement
    },
    [typeof Way, typeof WayTag[]]
  >`
    <div
      n@click=${(evt: any) => {
        handlePlanWayMenuClickOut(evt)
      }}
      class="addplan-modal-wrap"
    >
      <div class="addplan-modal-content">
        <button
          n@click=${handleClose}
          class="addplan-modal-close"
          type="button"
          aria-label="close"
        >
          <span class="addplan-modal-close-icon">&#xe620;</span>
        </button>
        <div class="addplan-modal-header">
          <div class="addplan-modal-title">${header}</div>
        </div>
        <form n@name="form" n@submit=${handleConfirm}>
          <div class="addplan-modal-body">
            <div class="form-group">
              <label>
                <span class="form-group-title">标题</span>
                <input
                  type="text"
                  class="form-input"
                  name="plan-title"
                  value="${plan.title}"
                  placeholder="请输入计划标题"
                  required
                />
              </label>
            </div>
            <div class="form-group form-textarea-wrap">
              <label>
                <span class="form-group-title">简介</span>
                <textarea
                  class="form-input form-textarea"
                  name="plan-description"
                  placeholder="请输入计划说明"
                  row="5"
                  cols="10"
                  required
                >
${plan.comment}</textarea
                >
              </label>
            </div>
            <div class="form-group">
              <span class="form-group-title">截止日期</span>
              <date-picker
                n@name="datePicker"
                format="YYYY-MM-DD"
                date="${plan.dueDate}"
              ></date-picker>
            </div>
            <div class="form-group form-group-way-wrap">
              <label>
                <span class="form-group-title">方向</span>
                <input
                  n@click=${showPlanWayMenu}
                  n@name="planWayInput"
                  type="text"
                  class="form-input"
                  name="plan-way"
                  value="${data.way}"
                  placeholder="请选择计划方向"
                  required
                />
              </label>
              <ul n@name="planWayMenu" class="plan-way-menu hidden">
                ${Object.keys(waysMap).map(way =>
                  Way(way, way => {
                    doms.planWayMenu.classList.add('hidden')
                    proxyData.way = way
                  }),
                )}
              </ul>
            </div>
            <div
              n@name="tagsContainer"
              class="form-group ${data.way === '无' ? 'hidden' : ''}"
            >
              <span class="form-group-title">标签</span>
              <div n@name="planTagsWrap" class="plan-tags-wrap">
                ${waysMap[data.way]?.map((tag, i) =>
                  WayTag(
                    tag,
                    () => toggleActive(tag, i),
                    data.tags.includes(tag),
                  ),
                ) ?? ''}
              </div>
            </div>
          </div>
          <div class="addplan-modal-footer">
            <button
              n@click=${handleClose}
              class="addplan-btn addplan-btn-cancel"
              type="button"
            >
              <span>取 消</span>
            </button>
            <button class="addplan-btn addplan-btn-confirm" type="submit">
              <span>确 定</span>
            </button>
          </div>
        </form>
      </div>
    </div>
  `

  const proxyData = reactive(data, (p, data) => {
    switch (p) {
      case 'way':
        doms.planWayInput.value = data.way
        if (data.way === '无') {
          doms.tagsContainer.classList.add('hidden')
        } else {
          doms.tagsContainer.classList.remove('hidden')
        }
        proxyData.tags = Array.from(
          waysMap[data.way as keyof typeof waysMap],
          () => '',
        )
        return
      case 'tags':
        const list = waysMap[data.way]
        const renderProps = list.map(
          (tag, i) => [tag, () => toggleActive(tag, i)] as [string, () => void],
        )
        renderMaps(doms.planTagsWrap, WayTag, components, ...renderProps)
        return
    }
  })

  document.body.append(el.dom)
  return el
}

export const addPlanModal = (
  planModalProps: Omit<PlanModalProps, 'header' | 'plan'>,
) => {
  PlanModal({
    header: '添加计划',
    ...planModalProps,
  })
}

export const editPlanModal = (
  planModalProps: Required<Omit<PlanModalProps, 'header'>>,
) => {
  PlanModal({
    header: '编辑计划',
    ...planModalProps,
  })
}

export default {
  PlanModal,
  addPlanModal,
  editPlanModal,
}
